#include "streams.h"
#include <initguid.h>
#include "MediaBridgeSourceFilter.h"

#define SOURCE_NAME L"MediaBridge Source Filter"

// Setup information
const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
    &MEDIATYPE_Video,				 // Major type
    &MEDIASUBTYPE_NULL				 // Minor type
};

const AMOVIESETUP_PIN sudpPins[] =
{
    { L"Output",					 // Pins string name
      FALSE,						 // Is it rendered
      TRUE,							 // Is it an output
      FALSE,						 // Are we allowed none
      FALSE,						 // And allowed many
      &CLSID_NULL,					 // Connects to filter
      NULL,							 // Connects to pin
      1,							 // Number of types
      &sudPinTypes					 // Pin information
    }
};

const AMOVIESETUP_FILTER sudMediaBridgeSourceFilter =
{
    &CLSID_MediaBridgeSourceFilter,	// Filter CLSID
    SOURCE_NAME,					// String name
    MERIT_DO_NOT_USE,				// Filter merit
    1,								// Number of pins
    sudpPins						// Pin information
};

// List of class IDs and creator functions for the class factory. This
// provides the link between the OLE entry point in the DLL and an object
// being created. The class factory will call the static CreateInstance
CFactoryTemplate g_Templates[] = {
    { SOURCE_NAME
    , &CLSID_MediaBridgeSourceFilter
    , CMediaBridgeSourceFilter::CreateInstance
    , NULL
    , &sudMediaBridgeSourceFilter }
  ,
    { SOURCE_NAME L" Properties"
    , &CLSID_MediaBridgeSourceFilterPropertyPage
    , NULL }
};

int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

CMediaBridgeSourceFilter::CMediaBridgeSourceFilter(LPUNKNOWN punk, HRESULT *phr) :
    CSource(NAME("DShowMediaBridgeSourceFilter"), punk, CLSID_MediaBridgeSourceFilter)
{
	*phr = S_OK;
	m_callBackInstance = NULL;
	return;
} 

CMediaBridgeSourceFilter::~CMediaBridgeSourceFilter() 
{
	if(m_callBackInstance == NULL)
	{
		m_callBackInstance->Release();
		m_callBackInstance = NULL;
	}

	delete m_pPin;
}

STDMETHODIMP CMediaBridgeSourceFilter::GetCurFile(LPOLESTR * ppszFileName, AM_MEDIA_TYPE *pmt)
{
	/* Thread-saftey */
	CAutoLock cAutoLockShared(&m_cSharedState);

	LPOLESTR filename = L"DirectShow MediaBridge";
	*ppszFileName = filename;
    return NOERROR;
}

STDMETHODIMP CMediaBridgeSourceFilter::Load(LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt)
{
	/* Thread-saftey */
	CAutoLock cAutoLockShared(&m_cSharedState);

	HRESULT phr = S_OK;

	/* Create the output pin for our filter */
	m_pPin = new CMediaBridgeSourceFilterPin(&phr, this);

	/* Create a new class to store information about us/graph in it */
	MediaBridge::MediaBridgeGraphInfo ^ graphInfo = gcnew MediaBridge::MediaBridgeGraphInfo();

	/* Set the media url sent */
	graphInfo->MediaUrl = gcnew System::String(lpwszFileName);
	
	/* Set the pointer to the filter graph */
	graphInfo->FilterGraph = System::IntPtr(this->GetFilterGraph());

	/* Store the pointer for our instance of the filter */
	graphInfo->SourceFilter = System::IntPtr(this);

	/* Do the callback into our managed code */
	MediaBridge::MediaBridgeManager::AddMediaGraphInfo(graphInfo);
	
    return phr;
}

STDMETHODIMP CMediaBridgeSourceFilter::InitializeVideo(int VideoPixelWidth, int VideoPixelHeight, int BitCount, DWORD FourCC, GUID MediaSubType)
{
	/* Thread-saftey */
	CAutoLock cAutoLockShared(&m_cSharedState);

	m_pPin->SetVideoDimensions(VideoPixelWidth, VideoPixelHeight, BitCount, FourCC, MediaSubType);
	return S_OK;
}

CUnknown *CMediaBridgeSourceFilter::CreateInstance(LPUNKNOWN punk, HRESULT *phr)
{
	CMediaBridgeSourceFilter *filter = new CMediaBridgeSourceFilter(punk, phr);
	return filter;
}


STDMETHODIMP CMediaBridgeSourceFilter::SetCallback(IMediaBridgeCallback *CallbackInstance)
{
	m_callBackInstance = CallbackInstance;

	if(m_callBackInstance == NULL)
		return S_OK;

	m_callBackInstance->AddRef();
	return S_OK;
}

IMediaBridgeCallback * CMediaBridgeSourceFilter::GetCallBackInstance()
{
	return m_callBackInstance;
}

// NonDelegatingQueryInterface
STDMETHODIMP CMediaBridgeSourceFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
    CheckPointer(ppv,E_POINTER);

    if (riid == IID_IMediaBridgeSourceFilter) 
	{
        return GetInterface((IMediaBridgeSourceFilter *) this, ppv);
	}
	else if (riid == IID_IMediaBridgeCallback) 
	{
        return GetInterface((IMediaBridgeCallback *) this, ppv);
    }
	else if (riid == IID_IFileSourceFilter) 
	{
        return GetInterface((IFileSourceFilter *)this, ppv);
    } 
	else 
	{
        return CSource::NonDelegatingQueryInterface(riid, ppv);
    }
}

STDMETHODIMP CMediaBridgeSourceFilter::Stop(void)
{
	return CSource::Stop();
}

